#include "AsyncMsg.h"

constexpr int s_DDItemLimitLen = 4096;

AsyncMsg::AsyncMsg(std::string account, std::string password, HANDLE_CONN conn)
    : m_AccountId(account), m_Password(password), m_Conn(conn)
{
    m_FixInfo = FixInfo{
        "5",
        "HD:IP=127.0.0.1",
        0, 0, ""};

    m_CachedBuf = new char[s_DDItemLimitLen]{};
}

AsyncMsg::~AsyncMsg()
{
    if (m_CachedBuf != nullptr)
    {
        delete[] m_CachedBuf;
    }
}

void AsyncMsg::SetCallback(int type)
{
    // 设置通用回调
    if (type == 1)
    {
        Fix_RegReplyCallFunc(0, (void *)(&AsyncMsg::OnSessionReply));
    }
    else if (type == 2)
    {
        Fix_RegReplyCallFunc(0, (void *)(&AsyncMsg::OnSessionReply2));
    }
}

bool AsyncMsg::OnSessionReply(HANDLE_CONN hConn, HANDLE_SESSION hSess, int nRecv)
{
    fmt::print("OnSessionReply thread id = {}\n", ::syscall(SYS_gettid));

    fmt::print("[OnSessionReply] {}, {}, {}\n", hConn, hSess, nRecv);
    g_AsyncMsg->ParseItemsToCache(hConn, hSess);

    return true;
}

bool AsyncMsg::OnSessionReply2(HANDLE_CONN hConn, HANDLE_SESSION hSess, int nRecv)
{
    fmt::print("OnSessionReply2 thread id = {}\n", ::syscall(SYS_gettid));

    fmt::print("[OnSessionReply2] {}, {}, {}\n", hConn, hSess, nRecv);
    g_AsyncMsg2->ParseItemsToCache(hConn, hSess);

    return true;
}

bool AsyncMsg::AsyncLoginEx()
{
    DDRequest login(m_Conn);

    login.Init("100015", m_FixInfo);

    login.AddParam(FID_TYPE, "1");
    login.AddParam(FID_CONTENT, m_AccountId);
    login.AddParam(FID_JMLX, "6");

    char pwd[256]{};
    strcpy(pwd, m_Password.data());
    int len = sizeof(pwd);
    Fix_UniEncode3rd(m_AccountId.data(), pwd, len);
    if (pwd[0] == '\0')
    {
        fmt::print("密码加密失败\n");
        return false;
    }
    login.AddParam(FID_JYMM, pwd);

    return login.AsyncSend();
}

std::string GetItem(HANDLE_SESSION hSess, int fidId)
{
    char tmp[256]{};
    int len = sizeof(tmp);
    return Fix_GetItem(hSess, fidId, tmp, len);
}

void AsyncMsg::ParseItemsToCache(HANDLE_CONN hConn, HANDLE_SESSION hSess)
{
    int errcode = Fix_GetCode(hSess);
    if (errcode <= 0)
    {
        FIX_INT64 errcode = Fix_GetCode(hSess);
        char errs[256]{};
        int errlen = sizeof(errs);
        Fix_GetErrMsg(hSess, errs, errlen);
        fmt::print("Reply error : [{}]{}\n", errcode, errs);

        return;
    }

    if (!m_IsLogin)
    {
        m_IsLogin.store(true);
        ConfirmLogin(hSess);
        m_Cv.notify_one();
    }

    int rowCnt = Fix_GetCount(hSess); // 获取记录数

    // 按记录数分配
    m_CacheRecords.resize(rowCnt);
    fmt::print("Parsing row count = {}\n ", rowCnt);
    for (int row = 0; row < rowCnt; ++row)
    {
        int colCnt = Fix_GetColumnCount(hSess, row);
        m_CacheRecord.clear();
        // fmt::print("column count = {}\n", colCnt);

        for (int col = 0; col < colCnt; ++col)
        {
            int fidId = -1;
            int cachedBufLen = s_DDItemLimitLen;
            if (!Fix_GetValWithIdByIndex(hSess, row, col, fidId, m_CachedBuf, cachedBufLen))
            {
                fmt::print("Fix_GetValWithIdByIndex failed..\n");
                //    logger->warn("Parse sepcified item[{}:{}] failed", row, col);
                continue;
            }

            m_CacheRecord.emplace(fidId, std::string(m_CachedBuf, cachedBufLen));
        }

        m_CacheRecords[row] = std::move(m_CacheRecord);
    }

    DoPrintLog();
}

void AsyncMsg::ConfirmLogin(HANDLE_SESSION hSess)
{
    m_FixInfo.nodeId = atoi(GetItem(hSess, FID_NODEID).c_str());
    m_FixInfo.sysId = atoi(GetItem(hSess, FID_YWLX).data());
    m_FixInfo.token = GetItem(hSess, FID_TOKEN);
}

void AsyncMsg::DoPrintLog()
{
    int logCnt = static_cast<int>(m_CacheRecords.size());
    std::string logstr;
    for (int i = 0; i < logCnt; ++i)
    {
        logstr.append(fmt::format("[Record({}:{})]", i, m_CacheRecords.size()));
        auto &record = m_CacheRecords.at(i);
        for (const auto &item : record)
        {
            logstr.append(fmt::format("({}:{})", item.first, item.second.c_str()));
        }
        logstr.push_back('\n');
    }

    logger->info(std::move(logstr));
}

void AsyncMsg::AsyncQueryStockAccount()
{
    DDRequest req(m_Conn);

    req.Init("310001", m_FixInfo);
    req.AddParam(FID_TOKEN, m_FixInfo.token);
    req.AddParam(FID_KHH, m_AccountId);
    req.AddParam(FID_ROWCOUNT, "10");
    req.AddParam(FID_BROWINDEX, "");

    if (req.AsyncSend())
    {
        return;
    }
    fmt::print("AsyncQueryStockAccount failed..");
}

void AsyncMsg::AsyncQueryRiskInfo()
{
    DDRequest req(m_Conn);

    req.Init("180001", m_FixInfo);
    req.AddParam(FID_TOKEN, m_FixInfo.token);
    req.AddParam(FID_KHH, m_AccountId);

    if (req.AsyncSend())
    {
        return;
    }
    fmt::print("AsyncQueryRiskInfo failed..");
}